Skip to content

recvmsg: compute cmsg nexthdr end without firsthdr#1583

Open
rootvector2 wants to merge 1 commit into
axboe:masterfrom
rootvector2:recvmsg-cmsg-nexthdr-end
Open

recvmsg: compute cmsg nexthdr end without firsthdr#1583
rootvector2 wants to merge 1 commit into
axboe:masterfrom
rootvector2:recvmsg-cmsg-nexthdr-end

Conversation

@rootvector2

Copy link
Copy Markdown
Contributor

Noticed io_uring_recvmsg_cmsg_nexthdr() computes the cmsg region end as
io_uring_recvmsg_cmsg_firsthdr(o, msgh) + o->controllen. firsthdr
returns NULL when o->controllen < sizeof(struct cmsghdr), so this
becomes a non-zero offset applied to a null pointer, which is undefined
behavior. Compute end directly as name + namelen + controllen so the
arithmetic is always on a real pointer; the value matches the old
expression when firsthdr would have succeeded.

In io_uring_recvmsg_cmsg_nexthdr() the cmsg region end is computed as
io_uring_recvmsg_cmsg_firsthdr(o, msgh) + o->controllen.  firsthdr
returns NULL when o->controllen < sizeof(struct cmsghdr), and the
addition becomes a non-zero offset applied to a null pointer, which is
undefined behavior.

Compute end directly as name + namelen + controllen so the arithmetic
is always on a real pointer.  The value is identical to the old
expression when firsthdr would have succeeded, and the function still
returns NULL for any cmsg that does not fit in the cmsg region.

Signed-off-by: rootvector2 <dxbnaveed.k@gmail.com>
@Kprateek283

Copy link
Copy Markdown
Contributor

Just curious, did you actually hit a crash with this in the production, or was it flagged by ubsan/a static analyzer?

@rootvector2

Copy link
Copy Markdown
Contributor Author

not a production crash, it was flagged by static analysis. when o->controllen < sizeof(struct cmsghdr), firsthdr returns NULL and end ends up as NULL + o->controllen, which is UB. computing it as name + namelen + controllen gives the same value whenever firsthdr would've returned non-NULL, just without the null-base arithmetic.

@axboe

axboe commented Jul 2, 2026

Copy link
Copy Markdown
Owner

When can o->controllen < sizeof(struct cmsghdr) occur, then?

@rootvector2

Copy link
Copy Markdown
Contributor Author

in the documented firsthdr then nexthdr loop it can't. nexthdr is only reached after firsthdr returned non-NULL, so o->controllen >= sizeof(struct cmsghdr) already holds and the + o->controllen is on a real pointer. the analyzer trips on it because nexthdr calls firsthdr again on its own, and in isolation that call can return NULL before the offset is applied.

so it's really a cleanup: dropping the redundant firsthdr and computing end from name + namelen + controllen gives the identical value without the null-base arithmetic. no behavior change in the normal flow.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants